# -*- coding: utf-8 -*-
"""
    @project: pythonProject
    @Author：HanYonghua
    @file： acmd.py
    @date：2025/7/23 17:42
    @blogs: https://www.ncatest.com.cn
"""

# -*- coding: utf-8 -*-
"""
    @project: pythonProject
    @Author：HanYonghua
    @file： acmd.py
    @date：2025/7/23 17:42
    @blogs: https://www.ncatest.com.cn
"""

import click
from functools import wraps


class CLIState:
    def __init__(self):
        self.mode = "user"  # user / enable / config
        self.current_interface = None
        self.interface_commands = {
            'ip': ip_cmd,
            'show': show_cmd,
            'help': help_cmd,
            'exit': exit_cmd,
            '?': help_cmd
        }


def privilege_required(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        ctx = click.get_current_context()
        state = ctx.ensure_object(CLIState)
        if state.mode == "user" and ctx.info_name not in ["enable", "exit", "help"]:
            click.echo("需要先进入特权模式 (enable)")
            ctx.abort()
        return f(*args, **kwargs)

    return wrapper


def config_mode_required(f):
    @wraps(f)
    @privilege_required
    def wrapper(*args, **kwargs):
        ctx = click.get_current_context()
        state = ctx.ensure_object(CLIState)
        if state.mode != "config" and ctx.info_name not in ["configure", "exit", "help"]:
            click.echo("需要先进入配置模式 (configure)")
            ctx.abort()
        return f(*args, **kwargs)

    return wrapper


class CiscoCLI(click.MultiCommand):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._state = CLIState()
        self._commands = {
            'enable': enable_cmd,
            'configure': configure_cmd,
            'show': show_cmd,
            'interface': interface_cmd,
            'exit': exit_cmd,
            'help': help_cmd,
            '?': help_cmd
        }

    def list_commands(self, ctx):
        state = ctx.ensure_object(CLIState)
        if state.mode == "config" and state.current_interface:
            return list(state.interface_commands.keys())
        return list(self._commands.keys())

    def get_command(self, ctx, cmd_name):
        state = ctx.ensure_object(CLIState)
        if state.mode == "config" and state.current_interface:
            return state.interface_commands.get(cmd_name)
        return self._commands.get(cmd_name)


@click.command()
def enable_cmd():
    """进入特权模式"""
    ctx = click.get_current_context()
    state = ctx.ensure_object(CLIState)
    state.mode = "enable"
    click.echo("已进入特权模式")


@click.command()
@privilege_required
def configure_cmd():
    """进入配置模式"""
    ctx = click.get_current_context()
    state = ctx.ensure_object(CLIState)
    state.mode = "config"
    click.echo("已进入配置模式")


@click.command()
@privilege_required
def show_cmd():
    """显示系统信息"""
    ctx = click.get_current_context()
    state = ctx.ensure_object(CLIState)
    if state.current_interface:
        click.echo(f"当前配置的接口: {state.current_interface}")
    click.echo("显示系统信息...")


@click.command()
@config_mode_required
@click.argument('ifname')
def interface_cmd(ifname):
    """配置指定接口 (例如: interface eth0)"""
    ctx = click.get_current_context()
    state = ctx.ensure_object(CLIState)
    state.current_interface = ifname
    click.echo(f"正在配置接口 {ifname}")


@click.command()
def ip_cmd():
    """IP地址配置"""
    ctx = click.get_current_context()
    click.echo("可用子命令:\n  address - 配置IP地址")


@click.command()
@click.argument('address')
def ip_address(address):
    """配置IP地址 (例如: ip address 192.168.1.1)"""
    ctx = click.get_current_context()
    state = ctx.ensure_object(CLIState)
    if state.current_interface:
        click.echo(f"为接口 {state.current_interface} 配置IP地址: {address}")
    else:
        click.echo("错误: 需要先选择接口 (使用interface命令)")


@click.command()
def exit_cmd():
    """退出当前模式"""
    ctx = click.get_current_context()
    state = ctx.ensure_object(CLIState)
    if state.mode == "config":
        if state.current_interface:  # 当前在接口配置模式
            state.current_interface = None
            click.echo("退出接口配置模式")
        else:  # 当前在全局配置模式
            state.mode = "enable"
            click.echo("退出配置模式")
    elif state.mode == "enable":
        state.mode = "user"
        click.echo("退出特权模式")
    else:
        ctx.exit()


@click.command()
@click.argument('command', required=False)
def help_cmd(command=None):
    """显示帮助信息"""
    ctx = click.get_current_context()
    cli = ctx.find_root().command
    state = ctx.ensure_object(CLIState)

    if command:
        cmd = cli.get_command(ctx, command)
        if cmd:
            click.echo(f"\n{command} 命令帮助:")
            click.echo(f"  描述: {cmd.help}")
            if hasattr(cmd, 'params'):
                for param in cmd.params:
                    if isinstance(param, click.Argument):
                        click.echo(f"  参数: {param.name} - {param.help or '无描述'}")
                    elif isinstance(param, click.Option):
                        opts = ', '.join(param.opts)
                        click.echo(f"  选项: {opts} - {param.help or '无描述'}")
        else:
            click.echo(f"未知命令: {command}")
    else:
        click.echo("\n可用命令:")
        if state.mode == "config" and state.current_interface:
            commands = ['ip', 'show', 'help', 'exit', '?']
        else:
            commands = {
                'user': ['enable', 'help', 'exit', '?'],
                'enable': ['configure', 'show', 'help', 'exit', '?'],
                'config': ['interface', 'show', 'help', 'exit', '?']
            }[state.mode]

        max_len = max(len(cmd) for cmd in commands)

        for cmd in commands:
            command_obj = cli.get_command(ctx, cmd)
            if command_obj:
                click.echo(f"  {cmd.ljust(max_len)}  {command_obj.help or '无描述'}")


def run_interactive():
    cli = CiscoCLI(help='思科风格CLI模拟器')
    state = CLIState()

    while True:
        prompt_suffix = {
            "user": "> ",
            "enable": "# ",
            "config": "(config)# ",
            "config-if": f"(config-if-{state.current_interface})# "
        }

        prompt = prompt_suffix["config-if"] if state.mode == "config" and state.current_interface else prompt_suffix[
            state.mode]

        try:
            cmd = input(prompt).strip()
            if not cmd:
                continue

            ctx = click.Context(cli, obj=state)
            with ctx:
                if cmd == "exit":
                    exit_cmd.callback()
                    if state.mode == "user":
                        break
                    continue

                parts = cmd.split()
                command = cli.get_command(ctx, parts[0])
                if not command:
                    click.echo(f"未知命令: {parts[0]}")
                    continue

                try:
                    # 处理ip address命令
                    if parts[0] == "ip" and len(parts) > 1 and parts[1] == "address":
                        if len(parts) > 2:
                            ctx.invoke(ip_address, address=parts[2])
                        else:
                            click.echo("错误: 需要指定IP地址 (例如: ip address 192.168.1.1)")
                    else:
                        # 处理其他命令
                        if len(parts) > 1:
                            ctx.invoke(command, ifname=parts[1] if parts[0] == 'interface' else None)
                        else:
                            ctx.invoke(command)
                except click.ClickException as e:
                    click.echo(f"错误: {e.format_message()}")
        except (KeyboardInterrupt, EOFError):
            click.echo("\n退出CLI")
            break
        except Exception as e:
            click.echo(f"系统错误: {str(e)}")


if __name__ == '__main__':
    run_interactive()